/**
 *          File: cm_utils.c
 *
 *        Create: 2014年12月19日 星期五 14时13分24秒
 *
 *   Discription:
 *
 *        Author: jmdvirus
 *
 *===========================================================================
 */
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <sys/time.h>
#include <unistd.h>
#endif
#include <sys/stat.h>
#include <sys/types.h>
//
// Common functions
//
#include "cm_utils.h"

int cm_walltime_set(CMWallTime *t, int year, int month, int day, int hour, int minute, int second)
{
    t->iYear = year;
    t->iMon = month;
    t->iDay = day;
    t->iHour = hour;
    t->iMinute = minute;
    t->iSecond = second;
    return 0;
}

int cm_walltime_in(CMWallTimeCondition *cond)
{

    time_t now = time(NULL);
    struct tm *tm = localtime(&now);

    char starttime[64] = {0};
    char endtime[64] = {0};
    char nowtime[64] = {0};
    char nowd[64] = {0};
    sprintf(nowd, "%04d%02d%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
    sprintf(nowtime, "%04d%02d%02d%02d%02d%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
            tm->tm_hour, tm->tm_min, tm->tm_sec);
    char nowt[64] = {0};
    sprintf(nowt, "%02d%02d%02d", tm->tm_hour, tm->tm_min, tm->tm_sec);

    switch (cond->iTimeType)
    {
        case CM_WALLTIME_TIMETYPE_EVERYDAY:
        {
            char startd[64] = {0};
            sprintf(startd, "%04d%02d%02d", cond->szStartTime.iYear, cond->szStartTime.iMon,
                    cond->szStartTime.iDay);
            char endd[64] = {0};
            sprintf(endd, "%04d%02d%02d", cond->szEndTime.iYear, cond->szEndTime.iMon,
                    cond->szEndTime.iDay);

            if (strcmp(startd, nowd) <= 0 && strcmp(nowd, endd) <= 0)
            {
                sprintf(starttime, "%02d%02d%02d", cond->szStartTime.iHour,
                        cond->szStartTime.iMinute, cond->szStartTime.iSecond);

                sprintf(endtime, "%02d%02d%02d", cond->szEndTime.iHour, cond->szEndTime.iMinute,
                        cond->szEndTime.iSecond);
                if (strcmp(starttime, nowt) <= 0 && strcmp(nowt, endtime) <= 0)
                {
                    return 1;
                }
            }
        }
        break;
        case CM_WALLTIME_TIMETYPE_MONTHDAY:
        {
            if (cond->szStartTime.iYear <= tm->tm_year && cond->szEndTime.iYear >= tm->tm_year
                && cond->szStartTime.iMon <= tm->tm_mon && cond->szEndTime.iMon >= tm->tm_mon
                && cond->szStartTime.iDay == tm->tm_mday)
            {
                sprintf(starttime, "%02d%02d%02d", cond->szStartTime.iHour,
                        cond->szStartTime.iMinute, cond->szStartTime.iSecond);
                sprintf(endtime, "%02d%02d%02d", cond->szEndTime.iHour, cond->szEndTime.iMinute,
                        cond->szEndTime.iSecond);
                if (strcmp(starttime, nowt) <= 0 && strcmp(nowt, endtime) <= 0)
                {
                    return 1;
                }
            }
        }
        break;
        case CM_WALLTIME_TIMETYPE_WEEK:
        {
            int nowweek = tm->tm_wday;
            if (nowweek != cond->iWeekDay)
                return -1;
            char startd[64] = {0};
            sprintf(startd, "%04d%02d%02d", cond->szStartTime.iYear, cond->szStartTime.iMon,
                    cond->szStartTime.iDay);
            char endd[64] = {0};
            sprintf(endd, "%04d%02d%02d", cond->szEndTime.iYear, cond->szEndTime.iMon,
                    cond->szEndTime.iDay);

            if (strcmp(startd, nowd) <= 0 && strcmp(nowd, endd) <= 0)
            {
                sprintf(starttime, "%02d%02d%02d", cond->szStartTime.iHour,
                        cond->szStartTime.iMinute, cond->szStartTime.iSecond);
                sprintf(endtime, "%02d%02d%02d", cond->szEndTime.iHour, cond->szEndTime.iMinute,
                        cond->szEndTime.iSecond);
                if (strcmp(starttime, nowt) <= 0 && strcmp(nowt, endtime) <= 0)
                {
                    return 1;
                }
            }
        }
        break;
        case CM_WALLTIME_TIMETYPE_YEARDAY:
        {
            if (tm->tm_year >= cond->szStartTime.iYear && tm->tm_year <= cond->szEndTime.iYear
                && tm->tm_mon == cond->szStartTime.iMon && tm->tm_mday == cond->szStartTime.iDay)
            {

                sprintf(starttime, "%02d%02d%02d", cond->szStartTime.iHour,
                        cond->szStartTime.iMinute, cond->szStartTime.iSecond);

                sprintf(endtime, "%02d%02d%02d", cond->szEndTime.iHour, cond->szEndTime.iMinute,
                        cond->szEndTime.iSecond);
                if (strcmp(starttime, nowtime) <= 0 && strcmp(nowtime, endtime) <= 0)
                {
                    return 1;
                }
            }
        }
        break;
        case CM_WALLTIME_TIMETYPE_ONCE:
        {
            sprintf(starttime, "%04d%02d%02d%02d%02d%02d", cond->szStartTime.iYear,
                    cond->szStartTime.iMon, cond->szStartTime.iDay, cond->szStartTime.iHour,
                    cond->szStartTime.iMinute, cond->szStartTime.iSecond);

            sprintf(endtime, "%04d%02d%02d%02d%02d%02d", cond->szEndTime.iYear,
                    cond->szEndTime.iMon, cond->szEndTime.iDay, cond->szEndTime.iHour,
                    cond->szEndTime.iMinute, cond->szEndTime.iSecond);
            if (strcmp(starttime, nowtime) == 0 && strcmp(nowtime, endtime) == 0)
            {
                return 1;
            }
        }
        break;
        default:
            return -1;
    }
    return 0;
}

int cm_parse_data(unsigned char *data, char *string)
{
    char p[128];
    char *str;
    char *token;
    int i = 0;
    int val = 0;

    strncpy(p, string, strlen(string));

    for (str = p;; str = NULL)
    {
        token = strtok(str, ",");
        if (token == NULL)
        {
            break;
        }
        else
        {
            sscanf(token, "%02x", &val);
            data[i++] = val;
        }
    }

    return i + 1;
}

int cm_parse_data_string(char *string, char *save, int arrsize, int maxlen, const char sign)
{
    if (string == NULL || save == NULL || arrsize < 0 || maxlen < 0)
        return -1;
#ifndef _WIN32
    int i = 0, j = 0;
    int counts = 0;
    char *pos = index(string, sign);
    if (!pos)
        return -2;
    while ((pos = index(pos, sign)))
    {
        pos++;
        counts++;
    };
    counts += 1;  // we find counts

    pos = string;
    memset(save, 0, arrsize * maxlen);
    for (i = 0; i < maxlen; i++)
    {
        if (i >= counts)
            break;  // only deal we find counts
        char *p = save + i * (arrsize);
        for (j = 0; j < arrsize; j++)
        {
            if (j == arrsize - 1 || *pos == sign || *pos == '\0')
            {
                *(p + j) = '\0';
                if ((pos = index(pos, sign)))
                    pos++;
                break;
            }
            *(p + j) = *pos++;
        }
    }
    return i;  // return what we realy deal, maybe not maxlen
#else
    return 0;
#endif
}

int cm_parse_data_char(unsigned char *data, char *string, int maxlen, const char *sign)
{
    char p[128];
    char *str;
    char *token;
    int i = 0;
    char val;

    strncpy(p, string, strlen(string));

    for (str = p;; str = NULL)
    {
        if (i >= maxlen)
            break;
        token = strtok(str, sign);
        if (token == NULL)
        {
            break;
        }
        else
        {
            sscanf(token, "%c", &val);
            data[i++] = val;
        }
    }

    return i;
}

int cm_parse_string_int(char *string, int *save, int maxlen, const char *sign)
{
    char p[128];
    char *str;
    char *token;
    int i = 0;
    int val = 0;

    strncpy(p, string, strlen(string));

    for (str = p;; str = NULL)
    {
        if (i >= maxlen)
            break;
        token = strtok(str, sign);
        if (token == NULL)
        {
            break;
        }
        else
        {
            sscanf(token, "%d", &val);
            save[i++] = val;
        }
    }

    return i;
}

#if 0
// (xx,xx);(xx,xx)
// We don't control if great then imageSize max size
int cm_parse_string_imagerects(char *string, CM_SDK_ImageSize *imageSize, const char *sign)
{
    if (!string || !imageSize) return -1;

    CM_SDK_ImageSize *inImage = imageSize;

    char tmp[512] = {0};
    sprintf(tmp, "%s", string);
    char *p = tmp;
    char *str = NULL;
    char *token = NULL;
    int i = -1;
    for (str = p; ; str = NULL) {
        token = strtok(str, sign);
        if (token == NULL) {
            break;
        } else {
            sscanf(token, "(%d,%d)", &inImage->iWidth, &inImage->iHeight);
            inImage++;   // goto next
            i++;
        }
    }

    return i+1;
}
#endif

int cm_clear_parenthesis(char *save, char *string)
{
    if (save == NULL || string == NULL)
        return -1;

    int len = strlen(string);
    if (string[0] != '(' && string[len - 1] != ')')
        return -2;

    int i = 0;
    int j = 1;
    if (string[0] != '(')
        j = 0;
    for (i = 0; i < len; i++)
    {
        if (string[i] == ')')
            break;
        save[i] = string[j++];
    }

    return 0;
}
int cm_clear_parenthesis_self(char *string)
{
    if (string == NULL)
        return -1;

    char save[1024] = {0};
    cm_clear_parenthesis(save, string);
    return sprintf(string, "%s", save);
}

int cm_remove_space(char *str)
{
    int len = strlen(str);
    char *p = str + len - 1;
    while (*p == ' ' || *p == '\n')
    {
        p--;
    }

    *(p + 1) = '\0';

    int indx = 0;
    p = str;
    while (*p++ == ' ')
    {
        indx++;
    }

    int i = 0;
    while (indx > 0)
    {
        if (indx >= len - 1)
        {
            str[i] = '\0';
            break;
        }
        str[i++] = str[indx++];
    }

    return 0;
}

int cm_remove_last_break(char *args)
{
    if (args == NULL)
        return -1;

    int len = strlen(args);

#if 0
    char *p = args + len - 1;
    while (p && *p == '\n') {
        *p = '\0';
        p--;
    }
#endif
    if (args[len - 1] == '\n')
        args[len - 1] = '\0';

    return 0;
}

int cm_clear_string_char(char *origin, char *save, char c)
{
    char *p = origin;
    char *s = save;
    while (p && *p != '\0')
    {
        if (*p != c)
        {
            *s++ = *p++;
        }
        else
        {
            p++;
        }
    }
    *s = '\0';
    return 0;
}

/////////////////////////////////////////////////////////////////////////////////
///////////////   Network
/////////////////////////////////////////////////////////////////////////////////
#include <errno.h>
#include <sys/types.h>
#ifndef _WIN32
#include <arpa/inet.h>
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#endif

///////////////
// Take String to Path and Name
// ex: /Path/Filename
// Warn: you must sure the path and name has enough space.
int cm_seperate_filename(char *orig, char *path, char *name)
{
    if (!orig)
        return -1;
#ifndef _WIN32

    char *p = rindex(orig, '/');
    // Has no path. Just save to name.
    if (!p)
    {
        if (name)
        {
            sprintf(name, "%s", orig);
        }
        return 0;
    }
    else
    {
        if (path)
        {
            int len = p - orig;
            strncpy(path, orig, len);
            if (path[len] != '\0')
                path[len] = '\0';
        }
        if (name)
        {
            // The p is '/'
            sprintf(name, "%s", p + 1);
        }
    }
#endif

    return 0;
}

#include "math.h"
// Convert int @value to char and save to @save,
// the return pointer to @save
// return NULL if fail
const char *cm_itoa(int value, char *save)
{
#if 0
#ifdef MIPS
    return NULL;
#else
    if (isnan(value)) return NULL;

    sprintf(save, "%d", value);
    return save;
#endif
#else
    return NULL;
#endif
}

// convert string to value to @out
// return < 0 fail
//        == 0 success
int cm_atoi(const char *value, int *out)
{
    int ret = sscanf(value, "%d", out);
    if (ret != 1)
    {
        return -1;
    }
    return 0;
}

///////////
// media operation
//

// codec parse of sps pps sde
// Some may be contain sde info, we need ignore it.
int cm_codec_parse_pps(char *pps, int lenpps)
{
    char *p = pps;  // remember the start position, use for cacultate the length.
    char *pn = pps;
    int donelen = 0;
    int lenreadpps = 0;
    while (1)
    {
        pn++;  // The first is 0x 00 00 00 01, skip it.
        if (donelen + 3 >= lenpps)
            break;
        // find next 0x 00 00 00 01
        if (*pn == 0x0 && *(pn + 1) == 0x0 && *(pn + 2) == 0x0 && *(pn + 3) == 0x01)
        {
            // char *now = pn;  // remeber the address.
            lenreadpps = pn - p;
            memmove(pps, p, lenreadpps);
            break;
        }
        pn++;
        donelen++;
    }
    return lenreadpps;
}

// @data ex: 00 00 00 01 [sps] 00 00 00 01 [pps]
/*
 * @data the data
 * @pps will save pps here
 * @sps will save sps here
 */
int cm_codec_parse(char *data, int len, char *pps, int *lenpps, char *sps, int *lensps)
{
    if (len <= 0 || !lensps || !lenpps || !sps || !pps || !data)
        return -1;
    char *p = data;
    char *ps = data;  // sps start position
    int donelen = 0;
    while (1)
    {
        if (donelen + 3 >= len)
            break;
        if (*p == 0x0 && *(p + 1) == 0x0 && *(p + 2) == 0x0 && *(p + 3) == 0x01)
        {
            ps = p;  // remember here.
        }
        int bok = 0;
        char *pn = p + 4;
        char *pns = pn;  // the pps start position
        while (1)
        {
            if (donelen + 3 >= len)
                break;
            if (*pn == 0x0 && *(pn + 1) == 0x0 && *(pn + 2) == 0x0 && *(pn + 3) == 0x01)
            {
                pns = pn;  // remember here.
                // Find it, now save pps and sps to the args.
                int lenout = pns - ps;
                memcpy(sps, ps, lenout);
                if (lensps)
                    *lensps = lenout;
                lenout = len - *lensps;
                memcpy(pps, pns, lenout);
                if (lenpps)
                    *lenpps = lenout;
                bok = 1;
                break;
            }
            pn++;
            donelen++;
        }
        if (bok)
            break;
        p++;
        donelen++;
    }
    *lenpps = cm_codec_parse_pps(pps, *lenpps);
    return 0;
}

// TODO: check it validation
int hexToByte(char *str, int ilen, char *save)
{
    int count = 0;
    char *s = str;
    for (s = str; ilen > 0; s += 2)
    {
        if (*s >= '0' && *s <= '9')
            save[count] = *s - '0';
        else if (*s >= 'A' && *s <= 'F')
            save[count] = *s - 'A' + 10;
        if (strlen(s) > 1)
        {
            save[count] *= 16;
            if (*(s + 1) >= '0' && *(s + 1) <= '9')
                save[count++] += (*(s + 1) - '0');
            if (*(s + 1) >= 'A' && *(s + 1) <= 'F')
                save[count++] += (*(s + 1) - 'A' + 10);
        }
    }
    return 0;
}

#ifndef _WIN32
#include <dirent.h>
#endif
#include <string.h>

int is_program_running(int cnts, const char *prog[])
{
    int ret = 0;
#ifndef _WIN32
    struct dirent *d = NULL;
    DIR *dir = opendir("/proc");
    if (!dir)
    {
        return -1;
    }

    while ((d = readdir(dir)) != NULL)
    {
        char cmdname[288] = {0};
        if (d->d_type != DT_DIR)
            continue;
        snprintf(cmdname, sizeof(cmdname), "/proc/%s/cmdline", d->d_name);
        if (access(cmdname, R_OK) == 0)
        {
            FILE *f = fopen(cmdname, "r");
            if (f)
            {
                char data[1024] = {0};
                // int n = fread(data, 1, 64, f);
                int n = 0;
                char tdata[1024] = {0};
                int nn = fread(tdata, 1, 1024, f);
                int i;
                char *pt = tdata;
                char *p = data;
                for (i = 0; i < nn; i++)
                {
                    if (*pt != '\0')
                    {
                        *p++ = *pt++;
                    }
                    else
                    {
                        pt++;
                    }
                    n++;
                }
                fclose(f);
                // printf("cmdline: %s, %s, %d\n", data, prog[1], n);
                if (n > 0)
                {
                    // It's program self.
                    if (strncmp(data, prog[0], strlen(prog[0])) == 0)
                    {
                        break;
                    }
                    int tcnts = 0;
                    for (i = 0; i < cnts; i++)
                    {
                        if (strstr((char *)data, prog[i + 1]) == NULL)
                            break;
                        tcnts++;
                    }
                    if (tcnts == cnts)
                    {
                        // printf("I find you. %s\n", prog[1]);
                        ret = 1;
                        break;
                    }
                }
            }
        }
    }
#endif

    return ret;
}

int cm_read_file_data(const char *filename, char **data, int *len)
{
    if (!filename || !data)
        return -1;
    FILE *f = fopen(filename, "r");
    if (!f)
        return -2;
    struct stat st;
    stat(filename, &st);
    if (len)
        *len = st.st_size;

    *data = (char *)malloc(*len + 1);
    int ret = fread(*data, 1, *len, f);
    fclose(f);

    if ((*data)[ret - 1] == '\n')
    {
        (*data)[ret - 1] = '\0';
    }
    else
    {
        (*data)[ret] = '\0';
    }
    return ret;
}

int cm_write_file_data(const char *filename, char *data, int len)
{
    if (!filename || !data || len <= 0)
        return -1;

    FILE *f = fopen(filename, "w");
    if (!f)
        return -2;
    int ret = 0;
    int n = fwrite(data, 1, len, f);
    if (n != len)
    {
        ret = -3;
    }
    else
    {
        ret = n;
    }
    fflush(f);
    fclose(f);
    return ret;
}

int cm_files_remove(const char *dir, int rdir)
{
#ifndef _WIN32
    struct dirent **dirent;
    int ret = scandir(dir, &dirent, NULL, NULL);
    if (ret < 0)
    {
        if (errno == ENOTDIR)
        {
            // this is file
            unlink(dir);
            return 0;
        }
    }
    else
    {
        int i = 0;
        for (i = 0; i < ret; i++)
        {
            if (strncmp(dirent[i]->d_name, ".", 1) == 0 || strncmp(dirent[i]->d_name, "..", 2) == 0)
            {
                continue;
            }
            if (dirent[i]->d_type == DT_DIR)
            {
                char nextpath[512] = {0};
                sprintf(nextpath, "%s/%s", dir, dirent[i]->d_name);
                cm_files_remove(nextpath, rdir);
                if (rdir)
                    rmdir(nextpath);
                continue;
            }
            char filepath[512] = {0};
            sprintf(filepath, "%s/%s", dir, dirent[i]->d_name);
            unlink(filepath);
            free(dirent[i]);
        }
        if (rdir)
            rmdir(dir);
    }
    free(dirent);
#endif
    return 0;
}

unsigned long cm_file_size(const char *name)
{
    struct stat st;
    int ret = stat(name, &st);
    if (ret < 0)
    {
        return 0;
    }
    else
    {
        return st.st_size;
    }
}

unsigned long cm_dir_size(const char *path)
{
    struct dirent **dirent;
    unsigned long globalSize = 0;
    int ret = scandir(path, &dirent, NULL, NULL);
    if (ret < 0)
    {
        if (errno == ENOTDIR)
        {
            return 0;
        }
    }
    else
    {
        int i = 0;
        for (i = 0; i < ret; i++)
        {
            if (strncmp(dirent[i]->d_name, ".", 1) == 0 || strncmp(dirent[i]->d_name, "..", 2) == 0)
            {
                free(dirent[i]);
                continue;
            }
            if (dirent[i]->d_type == DT_DIR)
            {
                char nextpath[512] = {0};
                snprintf(nextpath, sizeof(nextpath), "%s/%s", path, dirent[i]->d_name);
                globalSize += cm_dir_size(nextpath);
            }
            else if (dirent[i]->d_type == DT_REG)
            {
                char filepath[512] = {0};
                snprintf(filepath, sizeof(filepath), "%s/%s", path, dirent[i]->d_name);
                globalSize += cm_file_size(filepath);
            }
            free(dirent[i]);
        }
    }
    free(dirent);
    return globalSize;
}

const char *cm_time_string(time_t tm)
{
    static char tStr[16] = {0};
    time_t t = tm;
    if (tm <= 0)
    {
        t = time(NULL);
    }
    sprintf(tStr, "%ld", t);
    return tStr;
}

unsigned int cm_gettime_only_micro()
{
#ifndef _WIN32
    struct timeval tv;
    int ret = gettimeofday(&tv, NULL);
    if (ret != 0)
    {
        return 0;
    }
    return tv.tv_usec;
#else
    return 0;
#endif
}

unsigned long long cm_gettime_micro()
{
#ifndef _WIN32
    struct timeval tv;
    int ret = gettimeofday(&tv, NULL);
    if (ret != 0)
    {
        return 0;
    }
    return tv.tv_sec * 1000000 + tv.tv_usec;
#else
    return 0;
#endif
}

unsigned long long cm_gettime_milli()
{
#ifndef _WIN32
    struct timeval tv;
    int ret = gettimeofday(&tv, NULL);
    if (ret != 0)
    {
        return 0;
    }
    return ((unsigned long long)tv.tv_sec) * 1000 + (unsigned long long)tv.tv_usec / 1000;
#else
    return 0;
#endif
}

int cm_format_time(char *save, int max, char *format)
{
    time_t t = time(NULL);
    struct tm *tm = localtime(&t);
    return strftime(save, max, format, tm);
}

int cm_format_time_t(char *save, int max, char *format, time_t t)
{
    struct tm *tm = localtime(&t);
    return strftime(save, max, format, tm);
}

int cm_format_time_local(char *save, int max, char *format, struct tm *tm)
{
    return strftime(save, max, format, tm);
}

int cm_random_with_chars(char *result, int num, char *chars)
{
    int len = strlen(chars);
    srand((unsigned int)time(NULL));
    int i;
    for (i = 0; i < num; i++)
    {
        result[i] = chars[(rand() % len)];
    }
    return 0;
}

int cm_random_num(int min, int max)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    unsigned int t = tv.tv_usec;
    int v = rand_r(&t) % max;

    return v < min ? v + min : v;
}

int cm_random_with_num_char(char *result, int num)
{
    const char *num_char = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    return cm_random_with_chars(result, num, (char *)num_char);
}

int cm_random_with_num_char_sym(char *result, int num)
{
    const char *num_char = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz,=+";
    return cm_random_with_chars(result, num, (char *)num_char);
}

int cm_string_compare(const char *src, const char *dst)
{
    if (!src || !dst)
        return -1;

    size_t slen = strlen(src);
    size_t dlen = strlen(dst);
    size_t clen = slen > dlen ? slen : dlen;
#ifdef _WIN32
    return strnicmp(src, dst, clen);
#else
    return strncasecmp(src, dst, clen);
#endif
}

int _cm_isxdigit(int c)
{
    return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}

int _cm_isprint(int c)
{
    return 1;
}

uint32_t cm_hex2bin(void *bin, char hex[])
{
    uint32_t len, i;
    uint32_t x;
    uint8_t *p = (uint8_t *)bin;

    len = strlen(hex);

    if ((len & 1) != 0)
    {
        return -1;
    }

    for (i = 0; i < len; i++)
    {
        if (_cm_isxdigit((int)hex[i]) == 0)
        {
            return -2;
        }
    }

    for (i = 0; i < len / 2; i++)
    {
        sscanf(&hex[i * 2], "%2x", &x);
        p[i] = (uint8_t)x;
    }
    return len / 2;
}

void cm_bin2scr(void *bin, uint32_t len)
{
    uint32_t i, ofs;
    uint8_t c;
    uint8_t *mem = (uint8_t *)bin;
    printf("\n");

    for (ofs = 0; ofs < len; ofs += 16)
    {
        printf("\n%08X", ofs);
        for (i = 0; i < 16 && ofs + i < len; i++)
        {
            printf(" %02x", mem[ofs + i]);
        }
        while (i++ < 16)
        {
            printf("   ");
        }
        printf("    ");

        for (i = 0; i < 16 && ofs + i < len; i++)
        {
            c = mem[ofs + i];
            printf("%c", (c == '\t' || !_cm_isprint(c)) ? '.' : c);
        }
    }
}

int cm_get_wifi_signal(const char *dev)
{
    int size = 10240, signal = 0;
    char buf[10240] = {0};
    char *ptr;

    char iwconfigstr[128] = {0};
    sprintf(iwconfigstr, "iwconfig %s | grep Signal > /tmp/wifi_signal", dev);
    int nt = system(iwconfigstr);
    if (nt < 0)
    {
        return 0;
    }

    FILE *f = fopen("/tmp/wifi_signal", "r");
    if (!f)
        return 0;
    int n = fread(buf, 1, size, f);

    if (buf[0] != '\0' && n > 0)
    {
        ptr = strstr(buf, "Signal level=");
        if (ptr)
        {
            ptr += strlen("Signal level=");
            signal = atoi(ptr);
        }
    }
    fclose(f);

    return signal;
}
#ifndef _WIN32
#include <sys/statvfs.h>
#endif
unsigned long long cm_get_ubi_size(const char *dev)
{
#ifndef _WIN32
    struct statvfs st;
    int ret = statvfs(dev, &st);
    if (ret < 0)
    {
        return 0;
    }
    return (unsigned long long)st.f_bsize * st.f_blocks;
#else
    return 0;
#endif
}

unsigned long long cm_get_ubi_available(const char *dev)
{
#ifndef _WIN32
    struct statvfs st;
    int ret = statvfs(dev, &st);
    if (ret < 0)
    {
        return 0;
    }
    return st.f_bsize * st.f_bavail;
#else
    return 0;
#endif
}

unsigned long long cm_get_ubi_free(const char *dev)
{
#ifndef _WIN32
    struct statvfs st;
    int ret = statvfs(dev, &st);
    if (ret < 0)
    {
        return ret;
    }
    return st.f_bsize * st.f_ffree;
#else
    return 0;
#endif
}

unsigned short cm_litte_to_big(unsigned short v)
{
    unsigned short ret = 0;
    ret |= (v & 0xff) << 8;
    ret |= (v >> 8 & 0xff);
    return ret;
}

unsigned short cm_big_to_little(unsigned short v)
{
    unsigned short ret = 0;
    ret |= (v & 0xff) << 8;
    ret |= (v >> 8 & 0xff);
    return ret;
}

// from last to take string from split
// clear @save yourself,
// you must sure save big enough
int cm_take_out_last_string(const char *str, char split, char *save)
{
#ifndef _WIN32
    const char *pos = rindex(str, (int)split);
    if (pos)
    {
        strncpy(save, pos + 1, str + strlen(str) - pos - 1);
    }
#endif
    return 0;
}

unsigned long cm_get_file_size(const char *filename)
{
    unsigned long filesize = 0;
    FILE *fp = fopen(filename, "r");
    if (fp)
    {
        fseek(fp, 0L, SEEK_END);
        filesize = ftell(fp);
        fclose(fp);
    }
    return filesize;
}

int cm_wifi_signal_level(int signal)
{
    static int levels[4] = {-35, -50, -75, -90};
    if (signal < levels[3])
    {
        return 1;
    }
    else if (signal > levels[0])
    {
        return 5;
    }
    else if (signal < levels[0] && signal > levels[1])
    {
        return 4;
    }
    else if (signal < levels[1] && signal > levels[2])
    {
        return 3;
    }
    else if (signal < levels[2] && signal > levels[3])
    {
        return 2;
    }
    return 0;
}

// orig + v (ret value), used for one int value for return 2 values
// one for user defined, one for errno
// orig for errno , v for user set...
// 0x ff ff ff ff ff ff ff ff
//    r  r  orig        v  v
// r - reserved
// orig - errno (must > 0)
// v - user set value
int cm_retserrno(int orig, int v)
{
    if (orig < 0)
    {
        return ~(((~orig + 1) | (v << 8)) - 1);
    }
    else
    {
        return orig | (v << 8);
    }
}

int cm_retgerrno(int orig)
{
    if (orig < 0)
    {
        return ((~orig + 1) & 0x00ffff00) >> 8;
    }
    else
    {
        return (orig & 0x00ffff00) >> 8;
    }
}

int cm_retgret(int orig)
{
    if (orig < 0)
    {
        return ~(((~orig + 1) & 0x000000ff) - 1);
    }
    else
    {
        return orig & 0x000000ff;
    }
}

#ifdef _WIN32
#define popen  _popen
#define pclose _pclose
#endif

int cm_path_is_mounted(const char *path)
{
    if (!path)
        return -1;

    char *key = (char *)malloc(strlen("on ") + strlen(path) + 1);
    char buffer[512] = {0};
    sprintf(key, "on %s", path);

    FILE *file = popen("mount", "r");
    if (NULL == file)
    {
        return -2;
    }

    while (fgets(buffer, sizeof(buffer), file) != NULL)
    {
        if (strstr(buffer, key))
        {
            pclose(file);
            free(key);
            return 1;
        }
    }

    pclose(file);
    free(key);

    return 0;
}

unsigned long long cm_path_size_all(const char *path, const char *postfix)
{
    if (!path || !postfix)
        return -1;
    struct dirent *d = NULL;
    DIR *dir = opendir(path);
    if (!dir)
    {
        return -1;
    }

    unsigned long long all_size = 0;
    while ((d = readdir(dir)) != NULL)
    {
        if (d->d_type == DT_DIR)
            continue;
        if (strcasestr(d->d_name, "storybook.log"))
        {
            char fullpath[1024] = {0};
            snprintf(fullpath, sizeof(fullpath), "%s/%s", path, d->d_name);
            struct stat st;
            int ret = stat(fullpath, &st);
            if (ret == -1)
            {
                continue;
            }
            all_size += st.st_size;
        }
    }
    closedir(dir);
    return all_size;
}

size_t cm_path_file_count(const char *path, const char *postfix)
{
    if (!path || !postfix)
        return -1;
    struct dirent *d = NULL;
    DIR *dir = opendir(path);
    if (!dir)
    {
        return -1;
    }

    size_t all_count = 0;
    while ((d = readdir(dir)) != NULL)
    {
        if (d->d_type == DT_DIR)
            continue;
        if (strcasestr(d->d_name, "storybook.log"))
        {
            all_count += 1;
        }
    }
    closedir(dir);
    return all_count;
}

int cm_path_latest_file(const char *path, const char *postfix, char *result, size_t size_max)
{
    if (!path || !postfix)
        return -1;

    struct dirent *d = NULL;
    DIR *dir = opendir(path);
    if (!dir)
    {
        return -1;
    }

    struct dirent *find = NULL;
    time_t latest = 0;
    while ((d = readdir(dir)) != NULL)
    {
        if (d->d_type == DT_DIR)
            continue;
        if (strcasestr(d->d_name, "storybook.log"))
        {
            char fullpath[1024] = {0};
            snprintf(fullpath, sizeof(fullpath), "%s/%s", path, d->d_name);
            struct stat st;
            int ret = stat(fullpath, &st);
            if (ret == -1)
            {
                continue;
            }
            if (st.st_ctim.tv_sec > latest)
            {
                latest = st.st_ctim.tv_sec;
                find = d;
            }
        }
    }
    if (find)
    {
        snprintf(result, size_max - 1, "%s", find->d_name);
    }
    closedir(dir);
    return 0;
}

int cm_popen_wrap(const char *cmd, char *buf, size_t size, int maxline)
{
    if (!cmd || size <= 0 || !buf || maxline <= 0)
        return -1;

    size_t ret = 0;
    FILE *f = popen(cmd, "r");
    if (!f)
    {
        return -2;
    }
    char tmp[1024] = {0};
    int count = 0;
    while (fgets(tmp, 1024, f) != NULL)
    {
        if (count++ >= maxline)
            break;
        if (ret >= size)
            break;
        size_t l = strlen(tmp);
        if (ret + l > size)
            l = size - ret;
        strncpy(buf + ret, tmp, l);
        ret += l;
    }

    pclose(f);
    return ret;
}

int cm_vector_tostring(std::vector<std::string> &vecs, std::string &result, int markpre,
                       int markpost)
{
    if (markpre != -1)
    {
        result = std::to_string(markpre);
    }

    for (int i = 0; i < vecs.size(); i++)
    {
        result += vecs[i];
        if (i != vecs.size() - 1)
        {
            result += ",";
        }
    }
    if (markpost != -1)
    {
        result += std::to_string(markpost);
    }
    return 0;
}

#ifdef __MAIN_TEST_
int main()
{

    int v1 = cm_retserrno(0, 228);
    printf("1, %d, %x\n", v1, v1);
    int v2 = cm_retgerrno(v1);
    int v3 = cm_retgret(v1);
    printf("2, %d, %x\n", v2, v2);
    printf("3, %d, %x\n", v3, v3);

    printf("Test remove file\n");
    BenewSystem("touch /tmp/test_file");
    sleep(5);
    cm_files_remove("/tmp/test_file", 0);

    printf("Test remove dir\n");
    BenewSystem("mkdir -p /tmp/test_dir/low");
    BenewSystem("touch /tmp/test_dir/t1; touch /tmp/test_dir/t2");
    BenewSystem("touch /tmp/test_dir/low/x1");
    sleep(5);
    cm_files_remove("/tmp/test_dir", 1);
    printf("Test remove dir also\n");
    sleep(2);
    cm_files_remove("/tmp/test_dir", 1);
    return 0;
}
#endif

/*=============== End of file: cm_utils.c ==========================*/
